Pixi.js

Pixi is an extremely fast 2D rendering engine.

Pixi won’t affect the way you program so that you can use as much or as little of it as you want to, adapt it to your personal coding style, and integrate it seamlessly with other useful frameworks.

Check Awsome PIXI Tools!


01. Get Start

Setup demo

import * as PIXI from 'pixi.js'
let type = "WebGL"
if(!PIXI.utils.isWebGLSupported()){
    type = "canvas"
}
PIXI.utils.sayHello(type)

if pxix works fine, you will see a pixi logo in your console.

Stage & Render demo

let app = new PIXI.Application({width: 256, height: 256});
document.body.appendChild(app.view);

创建一个 PIXI 容器可以在HTML 中创建一个 Canvas,我们可以传很多参数进去,如宽高,分辨率等

app.renderer.view.height = "500";
app.renderer.view.style.display = "block";
app.renderer.autoResize = true;
app.renderer.resize(window.innerWidth, window.innerHeight);
  • app.reneder 可以调整整个 PIXI 应用在 HTML 内部的位置和样式

    所有关于整个 PIXI 应用位置的属性都由 renderer 控制

    有一个 scaleToWindow 函数可以用于将 canvas 铺满屏幕

  • app.stage 是一个舞台,所有 sprites 元素都被放在这个根元素中

    sprites 可以通过单图片文件、雪碧图以及纹理贴图等方式创建

Show Images demo

Pixi 使用 WebGL 和 GPU 快速渲染图像,所以需要把图像转化成 GPU 可处理的 texture 以及快速处理的 texture cache

let texture = PIXI.utils.TextureCache['images/a.png'];
let sprite = new PIXI.Sprite(texture);

通过 loader 可以有效的快速添加多个图像并创建 sprite

// load the image and run setup when it's done
PIXI.loader
    .add('/static/images/cat.png')
    .add('/static/images/cat1.png')
    .add('/static/images/cat2.png')
    .load(setup)

function setup () {
    // create sprite
    let cat = new PIXI.Sprite(PIXI.loader.resources['/static/images/cat.png'].texture)
    let cat1 = new PIXI.Sprite(PIXI.loader.resources['/static/images/cat1.png'].texture)
    let cat2 = new PIXI.Sprite(PIXI.loader.resources['/static/images/cat2.png'].texture)
	// show sprite
    this.app.stage.addChild(cat)
    this.app.stage.removeChild(cat)
    cat.visible = false
}

如上所示,在创建了 sprite 之后就可以添加 sprite 到 stage 中

Stage 是包含所有 sprite 的主要容器

Alias

为防止 API 变更,我们可以使用别名统一命名一些主要的对象和方法,例如

let Application = PIXI.Application,
    loader = PIXI.loader,
    resources = PIXI.loader.resources,
    Sprite = PIXI.Sprite;

let app = new Application({...})
let cat = new Sprite(resources["images/cat.png"].texture);

Sprite

有几种重要的属性

  • 位置

    cat.x = 96;
    cat.y = 96;
    // or
    cat.position.set(96, 96)
    
  • 大小

    cat.width = 80;
    cat.height = 120;
    
  • 比例

    cat.scale.x = 0.5;
    cat.scale.y = 0.5;
    // or
    cat.scale.set(0.5, 0.5);
    
  • 旋转

    cat.rotation = 0.5;
    
  • 原点

    Sprite 默认的原点位置在图片的左上角,但是通过两种方式进行修改

    // option 1, 值为长宽的百分比
    cat.anchor.set(0.5, 0.5) 
    // option 2, 值为像素
    // 如果图片大小为 64*64, 那么(32, 32)的原点就在中心
    cat.pivot.set(32, 32)
    

Tileset

雪碧图

let tileset = this.$PIXI.utils.TextureCache['/static/images/tileset.png']
let rectangle = new this.$PIXI.Rectangle(0, 64, 64, 64)
tileset.frame = rectangle
let rocket = new this.$PIXI.Sprite(tileset)
rocket.position.set(60, 60)
this.app.stage.addChild(rocket)

PIXI.Rectangle(x, y, width, height)

利用 Rectangle 定位,再用 Rectangle 去剪裁 Tileset 从而得到想要的图像。

Tileset Atlas 雪碧图集

雪碧图集是一种更加便捷处理图像的方式,他在雪碧图的基础上新增了一个包含各图像位置信息的 JSON 文件,这样结合使用就不需要去计算图像的具体坐标和大小了。

如果你正在用免费版的 Texture Packer,把 Algorithm 选项设为Basic,把 Trim mode 选项设为None,把 Extrude 选项设为0,把 Size constraints 选项设为 Any size ,把 PNG Opt Level 中所有的东西都滑到左边的 0位置。这就可以使得Texture Packer正常的输出你的纹理贴图集。

如果你做完了,点击 Publish 按钮。选择输出文件名和存储地址,把生成文件保存起来。你将会获得两个文件:一个叫做treasureHunter.json,另外一个就是treasureHunter.png。为了让目录干净些,我们把他俩都放到一个叫做images的文件夹里面去。

创建雪碧图集后,我们只需要像正常加载图片一样加载 JSON 文件即可

PIXI.loader
    .add('/static/images/treasureHunt.json')
    .load(setup)

function setup () {
    let tileset = PIXI.loader.resources['/static/images/treasureHunt.json'].textures
    let explorer = new this.$PIXI.Sprite(tileset['explorer'])
    let dungeon = new this.$PIXI.Sprite(tileset['dungeon'])
    explorer.position.set(40, 240)

    this.app.stage.addChild(dungeon, explorer)
}

Movement

PIXI 提供了一个 ticker 方法,称为 Game Loop,其实就是一个封装后的 requestAnimationFrame 函数。

function setup() {
  app.ticker.add(delta => gameLoop(delta));
}

function gameLoop(delta){
  sprite.x += 1;
}

这样 sprite 就会在 x 方向上以每秒 60 次的速度移动

  • 速度

    可以通过定义 vx, vy 去调整速度

    function gameLoop(delta){
      //Update the cat's velocity
      cat.vx = 1;
      cat.vy = 1;
    
      cat.x += cat.vx;
      cat.y += cat.vy;
    }
    

    在上面的例子里,只要调整 vx, vy 的值,其实就可以调节运动的速度

  • 键盘控制

    可以通过 shared/keyboard.js 中的函数去控制键盘

    import keyboard from 'src/shared/keyboard'
    
    let left = keyboard(37)
    let up = keyboard(38)
    let right = keyboard(39)
    let down = keyboard(40)
    
    left.press = () => {
        this.cat.vx = -5
    }
    left.release = () => {
        if (right.isDown) this.cat.vx = 5
        else this.cat.vx = 0
    }
    right.press = () => {
        this.cat.vx = 5
    }
    right.release = () => {
        if (left.isDown) this.cat.vx = -5
        else this.cat.vx = 0
    }
    
    app.ticker.add(delta => {
        this.cat.x += this.cat.vx
        this.cat.y += this.cat.vy
    }
    

Grouping

组合多个 Sprites 在一个 container,然后将这个 container 加入 stage

cat.position.set(16, 16)
bear.position.set(32, 32)
tiger.position.set(48, 48)

let animals = new PIXI.Container()
animals.add (cat, bear, tiger)
app.stage.addChild(animals)

// 或者组合里的子 Sprite
console.log(animals.children[0])
  • 局部位置

    在上例中,cat 的位置是相对于 container 而言的

    cat.position.x -> 16

  • 全局位置

    如果想要获得 cat 的全局位置,即相对于整个 stage 左上角的锚点的距离

    animals.toGlobal(cat.position) 或者

    cat.parent.toGlobal(cat.position) 或者

    cat.getGlobalPosition().x
    cat.getGlobalPosition().y
    
  • 同一组 Sprites 之间的距离

    cat.toLocal(cat.position, tiger).x

    cat.toLocal(cat.position, tiger).y

  • 高性能 Grouping

    如果用 PIXI.particles.ParticleContainer() 替换 PIXI.Container() ,Sprite 渲染的速度会快 2 到 5 倍,其他操作都不变,只是少了很多方法,例如精灵嵌套、过滤器、混合模式等等

Draw

PIXI 提供和 Canvas 一样的 API 去绘制图形,并且通过 GPU 渲染从而优化性能

  • 矩形

    let rectangle = new Graphics();
    rectangle.lineStyle(4, 0xFF3300, 1);
    rectangle.beginFill(0x66CCFF);
    rectangle.drawRect(0, 0, 64, 64);
    rectangle.endFill();
    rectangle.x = 170;
    rectangle.y = 170;
    app.stage.addChild(rectangle);
    
  • 圆形 graphics.drawCircle(x, y, radius);

  • 椭圆 graphics.drawEllipse(x, y, width, height);

  • 圆角矩形 graphics.drawRoundedRect(x, y, width, height, cornerRadius)

  • 文本

    PIXI 使用自己的文本对象在舞台上展示文本

    let style = new TextStyle({
      fontFamily: "Arial",
      fontSize: 36,
      fill: "white",
      stroke: '#ff3300',
      strokeThickness: 4,
      dropShadow: true,
      dropShadowColor: "#000000",
      dropShadowBlur: 4,
      dropShadowAngle: Math.PI / 6,
      dropShadowDistance: 6,
    });
    let message = new PIXI.Text("Hello Pixi!", style);
    app.stage.addChild(message);
    

Collision Detection

PIXI 提供一个 hitTestRectangle(spriteOne, spriteTwo) 函数检测两个 Sprites 是否碰撞,返回 Boolean 值